/*
    Project:        Home Power Control
    File:           HPCApplication.cpp
    Author:         christian@karunamusic.at
    Date:           01.2015
    Description:    Baseclass for the clients and the server.
                    Handles the -l, -c, -v, -h commandline arguments.
 */

#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QTextStream>
#include <QFileInfo>
#include <QSettings>
#include <QDate>
#include <QTime>
#include <QThread>
#include <iostream>
#include "Logger/HPCLogger.h"
#include "version.h"
#include "HPCApplication.h"
#include "HPCUserInput.h"

HPCApplication::HPCApplication( int& argc, char** argv, const QString& appName )
    : QCoreApplication( argc,argv ), m_LogScreen(0), m_LogFile(0), m_Run(false)
{
    QString ver = QString("%1.%2.%3.%4").arg(Version::MAJOR).arg(Version::MINOR).arg(Version::REVISION).arg(Version::BUILD);
    QCoreApplication::setApplicationName( appName );
    QCoreApplication::setApplicationVersion(ver);
    QCoreApplication::setOrganizationName("HPC");
    QCoreApplication::setOrganizationDomain("hpc.org");
}

HPCApplication::~HPCApplication()
{
    if ( m_LogScreen )
    {
        delete m_LogScreen;
    }
    if ( m_LogFile )
    {
        delete m_LogFile;
    }
}

void HPCApplication::Run()
{
    readConfig();
    QTextStream cout(stdout, QIODevice::WriteOnly);
    cout << "**********************************" << endl
         << "**   [H]ome [P]ower [C]ontrol   **" << endl
         << "**********************************" << endl
         << applicationName() << " v" << applicationVersion() <<  ", started at "
         << QDate::currentDate().toString("dd.MM.yyyy") << " "
         << QTime::currentTime().toString("hh:mm:ss") << endl << endl;

    if ( m_LogLevels[0] != disabled )
    {
        cout << "Screen Log:" << endl;
    }
    LOG(disabled,"***** " << applicationName() << " started. *****" );
    LOG(info, "loglevels: screen = " << m_LogLevels[0] << ", file = " << m_LogLevels[1] << ", database = " << m_LogLevels[2]);

    cout << "HPC commandline interface (type 'help' for more information)" << endl;
    QThread*      thrd = new QThread();
    HPCUserInput* cmdl = new HPCUserInput();
    cmdl->moveToThread(thrd);
    connect(cmdl,SIGNAL(command(QString)),this,SLOT(command(QString)));
    connect(thrd,SIGNAL(started()),       cmdl,SLOT(Run()));
    connect(cmdl,SIGNAL(finished()),      thrd,SLOT(quit()));
    connect(cmdl,SIGNAL(finished()),      cmdl,SLOT(deleteLater()));
    connect(thrd,SIGNAL(finished()),      thrd,SLOT(deleteLater()));
    m_Run = true;
    thrd->start();
}

void HPCApplication::command( QString cmd )
{
    LOG(info, "Command received: " << cmd);
    QStringList argv = cmd.split(" ",QString::SkipEmptyParts);

    QTextStream cout(stdout);

    m_Run = ( argv[0] != "exit" && argv[0] != "quit" );
    if ( m_Run )
    {
        if ( argv[0] == "help" )
        {
            QString topic = "";

            if ( argv.size() >= 2 )
            {
                topic = argv[1];
            }
            cliHelp(topic);
        }
        else if ( argv[0] == "loglevel" )
        {
            cliLogLevel(argv);
        }
    }
}

void HPCApplication::readConfig()
{
    HPCLogger *log = HPCLogger::getInstance();
    QFileInfo fi(applicationFilePath());
    QString logFile = fi.fileName() + ".log";

    QCommandLineParser parser;
    parser.setApplicationDescription( QString("[Home Power Control] - ") + applicationName() );
    parser.addHelpOption();
    parser.addVersionOption();

    parser.addOptions
    ({
         {{"c", "config"},
             translate("main", "read confiuration from <configfile>"),
             translate("main", "configfile")},
         {{"l", "loglevel"},
             translate("main", "set loglevel for '<screen>:<file>:<database>' to fatal, error, warning, info, debug, trace or leave empty to disable (ie. 'fatal:info:warning'."),
             translate("main", "levels")},
    });
    parser.process(*this);
    if ( parser.isSet("config") )
    {
        m_ConfigFile = parser.value("config");
    }
    else
    {
        m_ConfigFile = fi.fileName() + ".ini";
    }

    QSettings cfg( m_ConfigFile, QSettings::IniFormat );
    m_LogLevels[0] = log->StringToLogLevel( cfg.value("logger/screen").toString() );
    m_LogLevels[1] = log->StringToLogLevel( cfg.value("logger/file").toString() );
    m_LogLevels[2] = log->StringToLogLevel( cfg.value("logger/database").toString() );

    if ( parser.isSet("loglevel") )
    {
        QString logLevel = parser.value("loglevel");
        QStringList ll = logLevel.split(":");

        if ( ll[0] != "" )
        {
            m_LogLevels[0] = log->StringToLogLevel(ll[0]);
        }
        if ( ll[1] != "" )
        {
            m_LogLevels[1] = log->StringToLogLevel(ll[1]);
        }
        if ( ll[2] != "" )
        {
            m_LogLevels[2] = log->StringToLogLevel(ll[2]);
        }
    }
    m_LogScreen = new HPCLogScreen( m_LogLevels[0] );
    m_LogFile = new HPCLogFile( m_LogLevels[1],logFile );
}

void HPCApplication::cliHelp( QString topic )
{
    QTextStream cout(stdout);

    if ( topic == "" )
    {
        cout << "help\t\t\tthis helptext." << endl
             << "exit|quit\t\texit the client." << endl
             << "loglevel <dev> <lv>\tset the loglevel of <dev> to <lv>." << endl
             <<"\t\t\t  <dev> screen|file|db" << endl
             <<"\t\t\t  <lv>  disabled|fatal|error|warning|info|debug|trace" << endl;
    }
    else
    {
        if ( topic == "loglevel" )
        {
            cout << endl
                 << "loglevel <dev> <lv>\tset the loglevel of <dev> to <lv>." << endl
                 << endl
                 << "Print only messages with the given loglevel or higher." << endl
                 << endl
                 << "<dev> could be 'screen', 'file' or 'db'." << endl
                 << "<lv> is one of the loglevels:" << endl
                 << "  disabled\tturn of logging on the given device." << endl
                 << "  fatal\tprint only fatal errors (exceptions)." << endl
                 << "  error\tprint also common errors." << endl
                 << "  warning\tprint also warnings." << endl
                 << "  info\tprint also info messages (this is usually the default)." << endl
                 << "  debug\tprint also debug messages - mostly used for development purposes." << endl
                 << "  trace\tlogs nearly everything - generates a lot of lines!" << endl
                 << endl;
        }
    }
}

void HPCApplication::cliLogLevel( QStringList& argv )
{
    if ( argv.size() != 3 )
        return;

    QTextStream cout(stdout);

    if ( argv[1] == "screen" )
    {
        m_LogLevels[0] = HPCLogger::getInstance()->StringToLogLevel(argv[2]);
        m_LogScreen->LogLevel(m_LogLevels[0]);
        LOG(info,"Set loglevel for 'screen' to level " << HPCLogger::getInstance()->LogLevelToString(m_LogLevels[0]));
    }
    if ( argv[1] == "file" )
    {
        m_LogLevels[1] = HPCLogger::getInstance()->StringToLogLevel(argv[2]);
        m_LogFile->LogLevel(m_LogLevels[1]);
        LOG(info,"Set loglevel for 'file' to level " << HPCLogger::getInstance()->LogLevelToString(m_LogLevels[1]));
    }
}
